﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Fdd.Aspen.DomainModel.Entities;
using Fdd.Aspen.DomainModel.Repositories;
using System.Transactions;
using Fdd.Aspen.Infrastructure.Data;
using System.Data.Objects;
using System.Linq.Expressions;
using System.Diagnostics.Contracts;
using Fdd.Aspen.DomainModel.Repositories.Interfaces;

namespace Fdd.Aspen.Repositories
{
    public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        readonly IObjectContext _objectContext = null;
        readonly IObjectSet<TEntity> _objectSet = null;


        public BaseRepository(IObjectContext objectContext)
        {
            Contract.Requires(objectContext != null);
            Contract.Ensures(_objectContext != null);
            Contract.Ensures(_objectSet != null);

            _objectContext = objectContext;
            _objectSet = _objectContext.CreateObjectSet<TEntity>();
        }


        public IQueryable<TEntity> GetQuery()
        {
            Contract.Ensures(Contract.Result<IQueryable<TEntity>>() != null);

            return _objectSet;
        }


        public IEnumerable<TEntity> GetAll()
        {
            Contract.Ensures(Contract.Result<IEnumerable<TEntity>>() != null);
            
            return _objectSet.ToList();
        }


        public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> where)
        {
            Contract.Ensures(Contract.Result<IEnumerable<TEntity>>() != null);

            return _objectSet.Where(where);
        }


        public TEntity Single(Expression<Func<TEntity, bool>> where)
        {
            return _objectSet.SingleOrDefault(where);
        }


        public void Delete(TEntity entity)
        {
            Contract.Requires(entity != null);

            //TODO: Check this over, can be a problem if the code will be reused and the 
            //entity is already Attached since before.
            _objectSet.Attach(entity);
            _objectSet.DeleteObject(entity);
        }


        public void Add(TEntity entity)
        {
            Contract.Requires(entity != null);

            _objectSet.AddObject(entity);
        }


        [ContractInvariantMethod]
        private void ObjectInvariant()
        {
            Contract.Invariant(_objectContext != null);
            Contract.Invariant(_objectSet != null);
        }
    }
}
